#include <device_io.h>
#include <io_extend.h>
/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2023-09-09     SenyPC       the first version
 */
#include "device_io.h"
#include "device_data.h"
#include "io_extend.h"

#include <stdlib.h>

#define DBG_TAG "device_io"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>

rt_base_t _io_di_setting_nums = DEV_SETTING_DI_NUMS;
rt_base_t _io_di_pin[DEV_INNER_DI_NUMS] = {0};

rt_base_t _io_do_setting_nums = DEV_SETTING_DO_NUMS;
rt_base_t _io_do_pin[DEV_INNER_DO_NUMS] = {0};

#if (DEV_INNER_AI_NUMS > 0)
    #define AI_DEV_NAME        "adc1"      /* ADC 设备名称 */
    static rt_adc_device_t _dev_ai;

    rt_uint32_t _io_ai_setting_nums = DEV_SETTING_AI_NUMS;
    static rt_uint32_t _io_ai_channel[DEV_INNER_AI_NUMS] = {0};
#endif

#if (DEV_INNER_AO_NUMS > 0)
    #define AO_DEV_NAME        "dac1"      /* DAC 设备名称 */
    static rt_dac_device_t _dev_ao;

    rt_uint32_t _io_ao_setting_nums = DEV_SETTING_AO_NUMS;
    static rt_uint32_t _io_ao_channel[DEV_INNER_AO_NUMS] = {0};
#endif
static int io_init( void ) {
    _io_di_pin[0] = GET_PIN(A, 0);
    _io_di_pin[1] = GET_PIN(A, 1);
    _io_di_pin[2] = GET_PIN(A, 6);
    _io_di_pin[3] = GET_PIN(A, 7);
    _io_di_pin[4] = GET_PIN(D, 12);
    _io_di_pin[5] = GET_PIN(D, 13);
    _io_di_pin[6] = GET_PIN(E, 9);
    _io_di_pin[7] = GET_PIN(E, 11);
    _io_di_pin[8] = GET_PIN(B, 0);
    _io_di_pin[9] = GET_PIN(B, 1);
    _io_di_pin[10] = GET_PIN(B, 2);
    _io_di_pin[11] = GET_PIN(E, 7);
    _io_di_pin[12] = GET_PIN(E, 8);
    _io_di_pin[13] = GET_PIN(E, 10);


    _io_do_pin[0] = GET_PIN(E, 5);
    _io_do_pin[1] = GET_PIN(B, 9);
    _io_do_pin[2] = GET_PIN(B, 8);
    _io_do_pin[3] = GET_PIN(A, 15);
    _io_do_pin[4] = GET_PIN(E, 6);
    _io_do_pin[5] = GET_PIN(E, 13);
    _io_do_pin[6] = GET_PIN(E, 14);
    _io_do_pin[7] = GET_PIN(A, 8);
    _io_do_pin[8] = GET_PIN(B, 6);
    _io_do_pin[9] = GET_PIN(B, 7);

#if (DEV_INNER_AI_NUMS > 0)
    _io_ai_channel[0] = 10;         //PC0
    _io_ai_channel[1] = 12;         //PC2
    _io_ai_channel[2] = 13;         //PC3
    _io_ai_channel[3] = 3;         //PA3
#endif

#if (DEV_INNER_AO_NUMS > 0)
    _io_ao_channel[0] = 2;         //PA5
    _io_ao_channel[1] = 1;         //PA4
#endif

    for(int i = 0; i < DEV_INNER_DI_NUMS; i++)
    {
        rt_pin_mode(_io_di_pin[i], PIN_MODE_INPUT_PULLUP);
    }
    for(int i = 0; i < DEV_INNER_DO_NUMS; i++)
    {
        rt_pin_mode(_io_do_pin[i], PIN_MODE_OUTPUT);
        rt_pin_write(_io_do_pin[i], PIN_LOW);
    }

    return RT_EOK;
}
INIT_BOARD_EXPORT(io_init);

#if (DEV_INNER_AI_NUMS > 0)
static int io_ai_dev_init( void ) {
    rt_err_t ret = RT_EOK;
    _dev_ai = (rt_adc_device_t)rt_device_find(AI_DEV_NAME);
    if(_dev_ai == RT_NULL) {
        LOG_E("io_ai_dev_init failed! can't find %s device!", AI_DEV_NAME);
        return RT_ERROR;
    }
    for(int i = 0; i < DEV_INNER_AI_NUMS; i++) {
        ret = rt_adc_enable(_dev_ai, _io_ai_channel[i]);
        if(ret < 0) {
            LOG_E("io_ai_dev_init %s channel(%d) failed!", AI_DEV_NAME, _io_ai_channel[i]);
       }
    }
    return RT_EOK;
}
INIT_ENV_EXPORT(io_ai_dev_init);
#endif

#if (DEV_INNER_AO_NUMS > 0)
static int io_ao_dev_init( void ) {
    rt_err_t ret = RT_EOK;
    _dev_ao = (rt_dac_device_t)rt_device_find(AO_DEV_NAME);
    if(_dev_ao == RT_NULL) {
        LOG_E("io_ao_dev_init failed! can't find %s device!", AO_DEV_NAME);
        return RT_ERROR;
    }
    for(int i = 0; i < DEV_INNER_AO_NUMS; i++) {
        ret = rt_dac_enable(_dev_ao, _io_ao_channel[i]);
        if(ret < 0) {
            LOG_E("io_ao_dev_init %s channel(%d) failed!", AO_DEV_NAME, _io_ao_channel[i]);
        }
        rt_dac_write(_dev_ao, _io_ao_channel[i], 0);
    }
    return RT_EOK;
}
INIT_ENV_EXPORT(io_ao_dev_init);
#endif

uint8_t io_get_di(int pin) {
    if((pin >= 0) && (pin < DEV_INNER_DI_NUMS)) {
        return 1 - rt_pin_read(_io_di_pin[pin]);
    } else if(pin < _io_di_setting_nums) {
        return dev_di_data[pin];
    }else if(pin < DEV_X_BIT_NUMS) {
        if(dev_master_flag) {
            return io_get_ext_di(pin);
        } else {
            return dev_di_data[pin];
        }

    }
    return 0;
}


uint8_t io_get_do(int pin) {
    if((pin >= 0) && (pin < DEV_INNER_DO_NUMS)) {
        return rt_pin_read(_io_do_pin[pin]);
    } else if(pin < _io_do_setting_nums) {
        return dev_do_data[pin];
    } else if(pin < DEV_Y_BIT_NUMS) {
        if(dev_master_flag) {
            return io_get_ext_do(pin);
        } else {
            return dev_do_data[pin];
        }
    }
    return 0;

}

void io_set_do(int pin, rt_base_t value) {
    if((pin >= 0) && (pin < DEV_INNER_DO_NUMS)) {
        rt_pin_write(_io_do_pin[pin], value);
    } else if(pin < _io_do_setting_nums) {
        dev_do_data[pin] = value;
    } else if(pin < DEV_Y_BIT_NUMS) {
        if(dev_master_flag) {
            io_set_ext_do(pin,value);
        } else {
            dev_do_data[pin] = value;
        }
    }
}


int io_read_di(int start_addr, int nums, uint8_t *val) {
    int i = 0;
    int end_addr = start_addr + nums;
    if((start_addr >= 0) && (start_addr < _io_di_setting_nums)) {
        if(end_addr <= _io_di_setting_nums) {
            for(i = 0; i < nums; i++) {
                val[i] = io_get_di(start_addr + i);
            }
        } else if(start_addr < _io_di_setting_nums) {
            int inner_nums = _io_di_setting_nums -start_addr;
            for(i = 0; i < inner_nums; i++) {
                val[i] = io_get_di(start_addr + i);
            }
            if(end_addr <= DEV_X_BIT_NUMS) {
                if(dev_master_flag) {
                    io_read_ext_di(inner_nums, end_addr - inner_nums, &val[inner_nums]);
                } else {
                    memcpy(&val[inner_nums], &dev_di_data[inner_nums], end_addr - inner_nums);
                }
            } else {
                if(dev_master_flag) {
                    io_read_ext_di(inner_nums, DEV_X_BIT_NUMS - inner_nums, &val[inner_nums]);
                } else {
                    memcpy(&val[inner_nums], &dev_di_data[inner_nums], DEV_X_BIT_NUMS - inner_nums);
                }
            }
        }
        return 1;
    } else if(start_addr < DEV_X_BIT_ADDR) {
        if(end_addr <= DEV_X_BIT_NUMS) {
            if(dev_master_flag) {
                io_read_ext_di(start_addr, end_addr - start_addr, &val[0]);
            } else {
                memcpy(&val[0], &dev_di_data[start_addr], end_addr - start_addr);
            }
        } else {
            if(dev_master_flag) {
                io_read_ext_di(start_addr, DEV_X_BIT_NUMS - start_addr, &val[0]);
            } else {
                memcpy(&val[0], &dev_di_data[start_addr], DEV_X_BIT_NUMS - start_addr);
            }
        }
        return 1;
    }
    return 0;
}

int io_read_do(int start_addr, int nums, uint8_t *val) {
    int i = 0;
    int end_addr = start_addr + nums;
    if((start_addr >= 0) && (start_addr < _io_do_setting_nums)) {
        if(end_addr <= _io_do_setting_nums) {
            for(i = 0; i < nums; i++) {
                val[i] = io_get_do(start_addr + i);
            }
        } else if(start_addr < _io_do_setting_nums) {
            int inner_nums = _io_do_setting_nums -start_addr;
            for(i = 0; i < inner_nums; i++) {
                val[i] = io_get_do(start_addr + i);
            }
            if(end_addr <= DEV_Y_BIT_NUMS) {
                if(dev_master_flag) {
                    io_read_ext_do(inner_nums, end_addr - inner_nums, &val[inner_nums]);
                } else {
                    memcpy(&val[inner_nums], &dev_do_data[inner_nums], end_addr - inner_nums);
                }
            } else {
                if(dev_master_flag) {
                    io_read_ext_do(inner_nums, DEV_Y_BIT_NUMS - inner_nums, &val[inner_nums]);
                } else {
                    memcpy(&val[inner_nums], &dev_do_data[inner_nums], DEV_Y_BIT_NUMS - inner_nums);
                }
            }
        }
        return 1;
    } else if(start_addr < DEV_Y_BIT_NUMS) {
        if(end_addr <= DEV_Y_BIT_NUMS) {
            if(dev_master_flag) {
                io_read_ext_do(start_addr, end_addr - start_addr, &val[0]);
            } else {
                memcpy(&val[0], &dev_do_data[start_addr], end_addr - start_addr);
            }
        } else {
            if(dev_master_flag) {
                io_read_ext_do(start_addr, DEV_Y_BIT_NUMS - start_addr, &val[0]);
            } else {
                memcpy(&val[0], &dev_do_data[start_addr], DEV_Y_BIT_NUMS - start_addr);
            }
        }
        return 1;
    }
    return 0;
}

int io_write_do(int start_addr, int nums, uint8_t *val) {
    int i = 0;
    int end_addr = start_addr + nums;
    if((start_addr >= 0) && (start_addr < _io_do_setting_nums)) {
        if(end_addr <= _io_do_setting_nums) {
            for(i = 0; i < nums; i++) {
                io_set_do(start_addr + i, val[i]);
            }
        } else if(start_addr < _io_do_setting_nums) {
            int inner_nums = _io_do_setting_nums -start_addr;
            for(i = 0; i < inner_nums; i++) {
                io_set_do(start_addr + i, val[i]);
            }
            if(end_addr <= DEV_Y_BIT_NUMS) {
                if(dev_master_flag) {
                    io_write_ext_do(inner_nums, end_addr - inner_nums, &val[inner_nums]);
                } else {
                    memcpy(&dev_do_data[inner_nums], &val[inner_nums], end_addr - inner_nums);
                }
            } else {
                if(dev_master_flag) {
                    io_write_ext_do(inner_nums, DEV_Y_BIT_NUMS - inner_nums, &val[inner_nums]);
                } else {
                    memcpy(&dev_do_data[inner_nums], &val[inner_nums], DEV_Y_BIT_NUMS - inner_nums);
                }
            }
        }
        return 1;
    } else if(start_addr < DEV_Y_BIT_NUMS) {
        if(end_addr <= DEV_Y_BIT_NUMS) {
            if(dev_master_flag) {
                io_write_ext_do(start_addr, end_addr - start_addr, &val[0]);
            } else {
               memcpy(&dev_do_data[start_addr], &val[0], end_addr - start_addr);
            }
        } else {
            if(dev_master_flag) {
                io_write_ext_do(start_addr, DEV_Y_BIT_NUMS - start_addr, &val[0]);
            } else {
                memcpy(&dev_do_data[start_addr], &val[0], DEV_Y_BIT_NUMS - start_addr);
            }
        }
        return 1;
    }
    return 0;
}

#if (DEV_INNER_AI_NUMS > 0)
uint32_t io_get_ai(int channel) {
    if((channel >= 0) || (channel < DEV_INNER_AI_NUMS)) {
        return rt_adc_read(_dev_ai, _io_ai_channel[channel]);
    }
    return 0;
}

#ifdef FINSH_USING_MSH
#include <finsh.h>
static rt_err_t dev_ai(int argc, char **argv) {
    rt_uint32_t value = 0;
    value = io_get_ai(0);
    rt_kprintf("AI0's value is %d.\n", value);
    value = io_get_ai(1);
    rt_kprintf("AI1's value is %d.\n", value);
    value = io_get_ai(2);
    rt_kprintf("AI2's value is %d.\n", value);
    value = io_get_ai(3);
    rt_kprintf("AI3's value is %d.\n", value);
    return RT_EOK;
}
MSH_CMD_EXPORT(dev_ai, print dev_ai.);
#endif

#endif


#if (DEV_INNER_AO_NUMS > 0)
rt_err_t io_set_ao(int channel, rt_uint32_t value) {
    if((channel >= 0) || (channel < DEV_INNER_AO_NUMS)) {
        return rt_dac_write(_dev_ao, _io_ao_channel[channel], value);
    }
    return RT_EOK;
}

#ifdef FINSH_USING_MSH
#include <finsh.h>
static rt_err_t dev_ao(int argc, char **argv) {
    int channel = 0;
    rt_uint32_t value = 0;
    if (argc != 3) {
        return -RT_ERROR;
    }
    channel = atoi(argv[1]);
    value = atoi(argv[2]);
    io_set_ao(channel, value);
    rt_kprintf("set ao%d's value is %d.\n", channel, value);
    return RT_EOK;
}
MSH_CMD_EXPORT(dev_ao, set dev_ao.);
#endif

#endif
